# coding=utf-8
import random
from operator import itemgetter
import pymysql
import sys
import json

class UserBasedCF:
    def __init__(self):
        self.n_sim_user = 5  # 相似用户数
        self.n_rec_shop = 8  # 推荐数量
        self.trainSet = {}  # 用户-商家交互字典
        self.user_sim_matrix = {}  # 用户相似度矩阵
        self.all_shops = set()  # 所有商家集合
        self.db_config = {
            'host': '139.9.54.160',
            'port': 3306,
            'user': 'root',
            'password': '193750ww',
            'database': 'cy_cloud',
            'charset': 'utf8mb4'
        }

    def load_data(self):
        try:
            conn = pymysql.connect(**self.db_config)
            with conn.cursor() as cursor:
                # 加载收藏数据
                cursor.execute("SELECT customer_id, business_id FROM ct_store WHERE collect_status = 1")
                for customer_id, business_id in cursor.fetchall():
                    self.trainSet.setdefault(customer_id, set()).add(business_id)
                    self.all_shops.add(business_id)
                
                # 加载浏览历史数据(权重较低)
                cursor.execute("SELECT customer_id, business_id FROM ct_history WHERE browse_status = 1")
                for customer_id, business_id in cursor.fetchall():
                    self.trainSet.setdefault(customer_id, set()).add(business_id)
                    self.all_shops.add(business_id)
                
        except Exception as e:
            print(f"加载数据失败: {e}")
        finally:
            conn.close()

    def calculate_similarity(self):
        users = list(self.trainSet.keys())
        for i in range(len(users)):
            u = users[i]
            for j in range(i + 1, len(users)):
                v = users[j]
                common = len(self.trainSet[u] & self.trainSet[v])
                if common == 0:
                    continue
                # 计算Jaccard系数
                jaccard = common / len(self.trainSet[u] | self.trainSet[v])
                self.user_sim_matrix.setdefault(u, {})[v] = jaccard
                self.user_sim_matrix.setdefault(v, {})[u] = jaccard

    def recommend(self, target_user):
        target_user = int(target_user)
        # 用户无交互记录
        if target_user not in self.trainSet or not self.trainSet[target_user]:
            return random.sample(list(self.all_shops), min(self.n_rec_shop, len(self.all_shops)))

        # 获取相似用户
        similar_users = sorted(
            self.user_sim_matrix.get(target_user, {}).items(),
            key=itemgetter(1),
            reverse=True
        )[:self.n_sim_user]

        # 候选商家集合
        candidate = {}
        for user, sim in similar_users:
            for shop_id in self.trainSet[user]:
                if shop_id not in self.trainSet[target_user]:
                    candidate[shop_id] = candidate.get(shop_id, 0) + sim

        ranked = sorted(candidate.items(), key=itemgetter(1), reverse=True)
        rec_ids = [x[0] for x in ranked]

        # 补足推荐数量
        while len(rec_ids) < self.n_rec_shop and len(rec_ids) < len(self.all_shops):
            available = self.all_shops - set(rec_ids) - self.trainSet[target_user]
            if not available:
                break
            rec_ids.extend(random.sample(list(available), min(self.n_rec_shop - len(rec_ids), len(available))))

        return rec_ids[:self.n_rec_shop]

def recommend(user_id):
    cf = UserBasedCF()
    cf.load_data()
    cf.calculate_similarity()
    return cf.recommend(user_id)

if __name__ == "__main__":
    user_id = sys.argv[1] if len(sys.argv) > 1 else '1'
    results = recommend(user_id)
    print(json.dumps(results))